#include <sys/poll.h>
#include <unistd.h>
#include <stdlib.h>
#include "Log.hpp"
#include "EventLoop.hpp"

#define MAX 1024

using namespace ns_log;

class PollDispachter : public Dispatcher
{
public:
    // 初始化 select poll epoll 三者之一需要的数据块
    PollDispachter(EventLoop *evLoop);
    ~PollDispachter();
    // 添加节点
    int add();
    // 删除节点
    int remove();
    // 修改节点
    int modify();
    // 事件检测
    int dispatch(int timeout /* 单位：s*/);

private:
    int maxfd = 0;
    pollfd fds[MAX];
};

PollDispachter::PollDispachter(EventLoop *evLoop)
    : Dispatcher(evLoop)
{
    for (int i = 0; i < MAX; ++i)
    {
        fds[i].fd = -1;
        fds[i].events = 0;
        fds[i].revents = 0;
    }
}

int PollDispachter::add()
{
    int events = 0;
    if (_channel->_events & ReadEvent)
    {
        events |= POLLIN;
    }
    if (_channel->_events & WriteEvent)
    {
        events |= POLLOUT;
    }
    int i = 0;
    for (; i < MAX; ++i)
    {
        if (fds[i].fd == -1)
        {
            fds[i].events = events;
            fds[i].fd = _channel->_fd;
            maxfd = std::max(maxfd, i);
            break;
        }
    }
    // 检测文件描述符数超过上限
    if (i == MAX)
        return -1;
    return 0;
}
int PollDispachter::remove()
{
    for (int i = 0; i <= maxfd; ++i)
    {
        if (fds[i].fd == _channel->_fd)
        {
            close(fds[i].fd);
            fds[i].fd = -1;
            fds[i].events = 0;
            fds[i].revents = 0;
            if (maxfd == _channel->_fd)
                --maxfd;
            break;
        }
    }
    return 0;
}
int PollDispachter::modify()
{
    for (int i = 0; i <= maxfd; ++i)
    {
        if (fds[i].fd == _channel->_fd)
        {
            if (_channel->_events & ReadEvent)
            {
                fds[i].events |= POLLIN;
            }
            if (_channel->_events & WriteEvent)
            {
                fds[i].events |= POLLOUT;
            }

            break;
        }
    }
    return 0;
}
int PollDispachter::dispatch(int timeout)
{
    poll(fds, maxfd + 1, timeout);
    for (int i = 0; i <= maxfd; ++i)
    {
        int fd = fds[i].fd;
        if (fd == -1)
            continue;
        int events = fds[i].events;
        // 异常
        if (events & POLLERR || events & POLLHUP)
        {
            // 对方断开连接 删除fd 通过channelMap获得
            _channel = _evLoop->_channelMap[fd];
            remove();
            continue;
        }
        if (events & POLLIN)
        {
            _evLoop->activate(fd, ReadEvent);
        }
        if (events & POLLOUT)
        {
            _evLoop->activate(fd, WriteEvent);
        }
    }
    return 0;
}
PollDispachter::~PollDispachter()
{
    for (int i = 0; i <= maxfd; ++i)
    {
        if (fds[i].fd != -1)
        {
            close(fds[i].fd);
        }
    }
}